#ifndef  SHINY_CONTROL_HPP
# define SHINY_CONTROL_HPP

# include <SFML/Window.hpp>
# include <list>
# include "observatory.hpp"
# include "datatree.hpp"

namespace Shiny
{
    std::string       key2string(const sf::Keyboard::Key key);
    sf::Keyboard::Key string2key(const std::string str);

    class Control
    {
	typedef void (Control::*Procede)(const sf::Event);
	typedef bool (Control::*Compare)(const sf::Event) const;
    public:
	Control(const std::string& name, unsigned int joyId, unsigned int joyButton)
	{
	    _compare                         = &Control::CompareJoystick;
	    _method                          = &Control::ProcedeJoystick;
	    _name                            = name;
	    _event.JoystickButton.JoystickId = joyId;
	    _event.JoystickButton.Button     = joyButton;
	}

	Control(const std::string& name, sf::Keyboard::Key key)
	{
	    _compare                         = &Control::CompareKeyboard;
	    _method                          = &Control::ProcedeKeyboard;
	    _name           = name;
	    _event.Key.Code = key;
	}

	bool operator==(const std::string& name) const { return (_name == name);          }
	bool operator==(const sf::Event event)   const { return (this->*_compare)(event); }

	void operator()(const sf::Event event)
	{
	    (this->*_method)(event);
	}

	void ProcedeJoystick(const sf::Event event);
	void ProcedeKeyboard(const sf::Event event);
	bool CompareJoystick(const sf::Event event) const;
	bool CompareKeyboard(const sf::Event event) const;

	Observatory::Signal<const sf::Event> Pressed;
	Observatory::Signal<const sf::Event> Released;

      private:
	Procede                               _method;
	Compare                               _compare;
	std::string                           _name;
	sf::Event                             _event;
    };

    class Controls
    {
    public:
	typedef std::list<Control> ControlList;

	Controls(void) : _active(true)
	{
	}

	void     LoadData(Data data);
	Control* operator[](const std::string& str);
	void     operator()(const sf::Event);

	ControlList&       GetControls(void)       { return (_controls); }
	const ControlList& GetControls(void) const { return (_controls); }
	void               SetActive(bool s)       { _active = s;        }
	bool               IsActive(void)    const { return (_active);   }

    private:
	ControlList _controls;
	bool        _active;
    };

  class ControlManager
  {
  public:
    typedef std::list<Controls*> ControlWatchers;

    bool                    ReceiveEvent(const sf::Event);

    void                    Add(Controls&);
    void                    Delete(Controls&);

  private:
    void                    DeleteWatchers(void);

    ControlWatchers _watchers;
    ControlWatchers _toDel;
  };
}

#endif
